package net.chasing.androidbaseconfig.widget.rich;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.InputFilter;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.SpannedString;
import android.text.TextUtils;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.ImageSpan;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;

import net.chasing.androidbaseconfig.widget.edittext.MyEditText;
import net.chasing.androidbaseconfig.widget.rich.base.RichItem;
import net.chasing.androidbaseconfig.widget.rich.base.RichParserManager;

import java.util.ArrayList;
import java.util.List;

/**
 * 富文本输入EditText
 * 注意：
 * getRecommendSelection方法添加了判断，如果包含Topic标签，则Topic标签之前不能进行输入，
 * 点击Topic标签之前，光标会被移动至Topic标签之后
 */
public class RichEditText extends MyEditText implements View.OnKeyListener {
    /**
     * 为了避免死循环触发onSelectionChanged(),设置的两个标志变量
     */
    private int mNewSelStart, mNewSelEnd;
    private String mContentStr = ""; //控件当前展示的文本
    private StringBuilder myText; //自己维护的Text，带有<a></a>标签的文本，不是控件展示的文本，发送时使用该文本
    private List<RichItem> mLabelRichItemList; //记录所有转换前LabelText对应的RichItem
    private List<RichItem> mRichItemList; //记录所有转换后@Text对应的RichItem

    // 点击删除按钮删除富文本时，因为是通过setText改变文本，textChange捕捉到的是整串字符串，所以需要自己传递start、lengthAfter
    private boolean isChangeBySetRichText;

    private RichEditText.OnInputAtCharListener mOnInputAtCharListener;
    private RichEditText.OnDeleteTopicListener mOnDeleteTopicListener;

    public RichEditText(Context context) {
        super(context);
        init();
    }

    public RichEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public RichEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        myText = new StringBuilder();
        mRichItemList = new ArrayList<>();
        mLabelRichItemList = new ArrayList<>();
        setOnKeyListener(this);
    }

    //监听@字符的输入
    public void setOnInputAtCharListener(RichEditText.OnInputAtCharListener onInputAtCharListener) {
        mOnInputAtCharListener = onInputAtCharListener;
    }

    //监听topic标签的删除
    public void setOnDeleteTopicListener(RichEditText.OnDeleteTopicListener onDeleteTopicListener) {
        mOnDeleteTopicListener = onDeleteTopicListener;
    }

    //代替使用setText
    public void setRichText(String text) {
        setRichText(text, -1);
    }

    private void setRichText(String text, int cursorStart) {
        isChangeBySetRichText = true;
        myText.delete(0, myText.length());
        myText.append(text);
        SpannableStringBuilder spannableStr = RichParserManager.getInstance().parseRichItems(getContext(), myText.toString());
        setText(spannableStr);
        refreshRichInfo(false);
        if (cursorStart >= 0 && cursorStart < spannableStr.length())
            setSelection(cursorStart);
        else
            setSelection(spannableStr.length());
    }

    // 插入富文本
    public void insertRichText(String text) {
        int maxLength = 0;
        InputFilter[] filters = getFilters();
        for (InputFilter filter : filters) {
            if (filter instanceof InputFilter.LengthFilter) {
                maxLength = ((InputFilter.LengthFilter) filter).getMax();
                break;
            }
        }
        if (maxLength != 0 && myText.length() + text.length() > maxLength) return;

        int trulyStart = getTrulyPosition(getSelectionStart());
        int trulyEnd = getTrulyPosition(getSelectionEnd());
        myText.replace(trulyStart, trulyEnd, text);
        setRichText(myText.toString(), getSelectionStart() + RichParserManager.getInstance().parserLabelTextToRich(text).length());
    }

    // 用富文本替换之前占位的@字符
    public void replaceAtChar(String text) {
        int maxLength = 0;
        InputFilter[] filters = getFilters();
        for (InputFilter filter : filters) {
            if (filter instanceof InputFilter.LengthFilter) {
                maxLength = ((InputFilter.LengthFilter) filter).getMax();
                break;
            }
        }
        if (maxLength != 0 && myText.length() + text.length() - 1 > maxLength) return;

        int trulyEnd = getTrulyPosition(getSelectionEnd());
        int trulyStart = trulyEnd - 1;
        myText.replace(trulyStart, trulyEnd, text);
        setRichText(myText.toString(), getSelectionStart() - 1 + RichParserManager.getInstance().parserLabelTextToRich(text).length());
    }

    //添加Topic标签，如果文本包含标签了，就进行替换，保持只有一个Topic标签，且Topic标签处于文本最前
    public void changeTopic(String topicLabel) {
        setRichText(TopicRichParser.getInstance().changeTopicText(myText.toString(), topicLabel),
                RichParserManager.getInstance().parserLabelTextToRich(topicLabel).length());
    }

    //获取需要发送给服务器的包含<a></a>的文本
    public String getRichText() {
        return myText.toString();
    }

    private boolean isRefresh;

    //每次修改文本都需要进行重新计算富文本位置并重新设置ClickableSpan
    private void refreshRichInfo(boolean needRefreshClickSpan) {
        boolean hadPreRichItem = mRichItemList.size() > 0;
        AtRichParser.getInstance().resetTargetStr(myText.toString());
        TopicRichParser.getInstance().resetTargetStr(myText.toString());
        mRichItemList.clear();
        mRichItemList.addAll(RichParserManager.getInstance().getAllSimpleRichItem(getContext(), myText.toString()));
        mLabelRichItemList.clear();
        mLabelRichItemList.addAll(RichParserManager.getInstance().getAllRichItem(myText.toString()));

        if (needRefreshClickSpan && hadPreRichItem) {
            SpannableStringBuilder spannableStr = RichParserManager.getInstance().parseRichItems(getContext(), myText.toString());
            int index = getSelectionStart();
            isRefresh = true;
            setText(spannableStr);
            setSelection(index);
        }
    }

    /**
     * 监听删除按键，执行删除动作
     */
    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        //按下键盘时会出发动作，弹起键盘时同样会触发动作
        if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) {
            if (startStrEndWithRichItem() && getSelectionStart() == getSelectionEnd()) {
                int startPos = getSelectionStart();
                final String startStr = mContentStr.substring(0, startPos);

                //获取话题,并计算话题长度
                int length = 1;
                for (RichItem richItem : mRichItemList) {
                    if (richItem.getEndPosition() == startPos) {
                        length = richItem.getRichText().length();
                        if (mOnDeleteTopicListener != null) {
                            RichItem firstRichItem = TopicRichParser.getInstance().getSimpleFirstRichItem();
                            if (firstRichItem != null && firstRichItem.getEndPosition() == richItem.getEndPosition())
                                mOnDeleteTopicListener.onDeleteTopic();
                        }
                        break;
                    }
                }

                clearFocus();
                requestFocus();

                int trulyStart = getTrulyPosition(startStr.length() - length);
                int trulyEnd = getTrulyPosition(startStr.length());
                myText.replace(trulyStart, trulyEnd, "");

                int selectIndex = -1;
                for (RichItem richItem : mRichItemList) {
                    if (richItem.getEndPosition() == startPos) {
                        selectIndex = startPos - richItem.getRichText().length();
                        break;
                    }
                }
                setRichText(myText.toString(), selectIndex);
                return true;
            }
        }
        return false;
    }

    /**
     * 判断光标后面是否是一个"富文本"
     * 如果某个富文本第一个字符的前一个位置索引等于当前光标索引，
     * 如果光标后面是个“富文本”，返回true
     */
    private boolean endStrStartWithRichItem() {
        int endPos = getSelectionEnd();
        for (RichItem richItem : mRichItemList) {
            if (richItem.getStartPosition() == endPos)
                return true;
        }
        return false;
    }

    /**
     * 判断光标前面是否是一个"富文本"
     * 如果某个富文本最后一个字符的下一个位置索引等于当前光标索引，
     * 如果光标前面是个“富文本”，返回true
     */
    public boolean startStrEndWithRichItem() {
        int startPos = getSelectionStart();
        for (RichItem richItem : mRichItemList) {
            if (richItem.getEndPosition() == startPos)
                return true;
        }
        return false;
    }

    @Override
    public void setSelection(int start, int stop) {
        if (0 <= start && stop <= getText().toString().length()) {
            super.setSelection(start, stop);
        }
    }

    @Override
    public void setSelection(int index) {
        if (index >= 0)
            super.setSelection(index);
    }

    @Override
    protected void onSelectionChanged(int selStart, int selEnd) {
        try {
            selectChanged(selStart, selEnd);
            super.onSelectionChanged(selStart, selEnd);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void selectChanged(int selStart, int selEnd) {
        if (selStart == mNewSelStart && selEnd == mNewSelEnd)
            return;
        //校准左边光标
        int targetStart = getRecommendSelection(selStart);
        targetStart = targetStart == -1 ? selStart : targetStart;
        //校准右边光标
        int targetEnd = getRecommendSelection(selEnd);
        targetEnd = targetEnd == -1 ? selEnd : targetEnd;
        //保存新值
        mNewSelStart = targetStart;
        mNewSelEnd = targetEnd;
        //更新选中区域
        setSelection(targetStart, targetEnd);
    }

    /**
     * 掐头去尾,取中间字符串中的富文本
     *
     * @return 由于富文本无法选中, 所以返回一个合适的位置(返回-1表示不做特殊处理)
     */
    private int getRecommendSelection(int pos) {
        String text = mContentStr;
        if (TextUtils.isEmpty(text)) {
            return -1;
        }

        int index = -1;
        RichItem firstRichItem;
        for (RichItem richItem : mRichItemList) {
            if (mRichItemList.indexOf(richItem) == 0 && pos < richItem.getEndPosition()) {
                TopicRichParser.getInstance().resetTargetStr(myText.toString());
                firstRichItem = TopicRichParser.getInstance().getFirstRichItem();
                if (firstRichItem != null) { //代表第一个RichItem是topic的，则将光标移到topic后面，topic标签前面不能输入
                    index = richItem.getEndPosition();
                    break;
                }
            }
            if (richItem.getStartPosition() >= pos) {
                break;
            } else if (richItem.getEndPosition() > pos) {
                int start = pos - richItem.getStartPosition();
                int end = richItem.getEndPosition() - pos;
                index = start <= end ? richItem.getStartPosition() : richItem.getEndPosition();
                break;
            }
        }
        return index;
    }

    // lengthBefore不等于0代表是选中某段文字
    // lengthAfter不等于0代表有新文本
    @Override
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
        super.onTextChanged(text, start, lengthBefore, lengthAfter);
        if (isRefresh) {
            isRefresh = false;
            return;
        }
        if (lengthAfter == 1 && mOnInputAtCharListener != null) {
            //当输入了一个字符之后，判断该字符是不是@
            char c = text.toString().charAt(start);
            if (c == '@') {
                mOnInputAtCharListener.onInputAtChar();
            }
        }

        mContentStr = text.toString();

        if (!isChangeBySetRichText && myText != null) { //不是手动插入形式的，即用户输入的普通文本，才进行myText的文本替换
            int trulyStart = getTrulyPosition(start), trulyEnd = getTrulyPosition(start + lengthBefore);
            if (lengthBefore != 0 && lengthAfter == 0) { //删除选中字段
                myText.replace(trulyStart, trulyEnd, "");
            } else {
                String substring = text.toString().substring(start, start + lengthAfter);
                if (lengthBefore != 0) //不等于0代表替换选中字段
                    myText.replace(trulyStart, trulyEnd, substring);
                else
                    myText.insert(trulyStart, substring);
            }
            refreshRichInfo(true);
        }
        isChangeBySetRichText = false;
    }

    /**
     * 根据EditText上光标的位置pos，推倒出MyText对应的光标实际位置
     */
    private int getTrulyPosition(int pos) {
        if (mRichItemList == null || mRichItemList.size() == 0) return pos;
        int result = pos;
        RichItem richItem;
        for (int i = 0; i < mRichItemList.size(); i++) {
            richItem = mRichItemList.get(i);
            if (pos <= richItem.getStartPosition()) {
                return result;
            } else {
                result = mLabelRichItemList.get(i).getEndPosition() + pos - mRichItemList.get(i).getEndPosition();
            }
        }
        return result;
    }

    // 输入了@字符的监听回调
    public interface OnInputAtCharListener {
        void onInputAtChar();
    }

    public interface OnDeleteTopicListener {
        void onDeleteTopic();
    }

    /**
     * 在文本最后添加富文本
     *
     * @param richText 要显示的富文本
     * @param color    富文本颜色
     */
    public void addRichHintTextBefore(String richText, final int color) {
        addRichHintText(richText, color);
    }

    /**
     * 添加富文本
     *  @param richText 要显示的富文本
     * @param color    富文本颜色
     */
    private void addRichHintText(String richText, final int color) {
        if (TextUtils.isEmpty(richText)) return;
        SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
        SpannableString spannableString = new SpannableString(richText);
        ForegroundColorSpan span = new ForegroundColorSpan(color);
        spannableString.setSpan(span, 0, richText.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
        spannableStringBuilder.append(spannableString);
        spannableStringBuilder.append(getHint());
        setHint(spannableStringBuilder);
    }

    //在hint前添加图标
    public void setRichHintImg(int imgRes, String msg) {
        String space = "    ";
        msg = space + msg;//添加占位符，后面用于替换成图标
        SpannableString spannableString = new SpannableString(msg);
        int imgSize = (int) getTextSize() + 8;
        Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(), imgRes);
        Bitmap scaleBitmap = Bitmap.createScaledBitmap(bitmap, imgSize, imgSize, true);
        bitmap.recycle();
        ImageSpan span = new ImageSpan(getContext(), scaleBitmap);
        //图标后面留两个空格
        spannableString.setSpan(span, space.length() - 3, space.length() - 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        setHint(spannableString);
    }

    //通过富文本形式，改变hint的字体大小，与text的字体大小区分开
    public void setHintWithTextSize(String msg, int textSize) {
        if (TextUtils.isEmpty(msg)) return;
        SpannableString ss = new SpannableString(msg);
        AbsoluteSizeSpan ass = new AbsoluteSizeSpan(textSize, true);
        ss.setSpan(ass, 0, ss.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        setHint(new SpannedString(ss)); // 一定要进行转换,否则属性会消失
    }
}
